package com.sky.service.common.impl;

import cn.hutool.core.collection.CollectionUtil;
import com.github.pagehelper.Page;
import com.github.pagehelper.PageHelper;
import com.sky.constant.MessageConstant;
import com.sky.constant.RedisConstant;
import com.sky.constant.StatusConstant;
import com.sky.dto.CategoryDTO;
import com.sky.dto.CategoryPageQueryDTO;
import com.sky.exception.DeletionNotAllowedException;
import com.sky.mapper.common.CategoryMapper;
import com.sky.mapper.common.DishMapper;
import com.sky.mapper.admin.SetmealMapper;
import com.sky.pojo.Category;
import com.sky.result.PageResult;
import com.sky.result.Result;
import com.sky.service.common.CategoryService;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;

import java.util.Collections;
import java.util.List;
import java.util.concurrent.TimeUnit;

/**
 * 菜品分类、套餐分类业务处理层实现类
 *
 * @Author: Zhy
 * @Date: 2025-01-15 17:22
 * @Version: 1.0
 */
@Service
@Slf4j
@RequiredArgsConstructor
public class CategoryServiceImpl implements CategoryService {
	private final CategoryMapper categoryMapper;
	private final DishMapper dishMapper;
	private final SetmealMapper setmealMapper;
	private final RedisTemplate redisTemplate;

	/**
	 * 新增分类
	 *
	 * @return:
	 * @param:
	 */
	@Override
	public Result<String> saveCategory(CategoryDTO categoryDTO) {
		Category category = new Category();
		// 属性拷贝
		BeanUtils.copyProperties(categoryDTO, category);

		// 分类状态默认为禁用状态0
		category.setStatus(StatusConstant.DISABLE);

		categoryMapper.insertCategory(category);

		// 清空缓存
		redisTemplate.delete(RedisConstant.CATEGORY_CACHE_PREFIX + category.getType());

		return Result.success();
	}

	/**
	 * 分页查询
	 *
	 * @return:
	 * @param:
	 */
	@Override
	public Result<PageResult> selectPageQuery(CategoryPageQueryDTO categoryPageQueryDTO) {
		// 开启分页插件
		PageHelper.startPage(categoryPageQueryDTO.getPage(), categoryPageQueryDTO.getPageSize());

		// 下一条sql进行分页，自动加入limit关键字分页
		Page<Category> page = categoryMapper.selectPageQuery(categoryPageQueryDTO);
		PageResult pageResult = new PageResult(page.getTotal(), page.getResult());

		return Result.success(pageResult);
	}

	/**
	 * 根据id删除分类
	 *
	 * @return:
	 * @param:
	 */
	@Override
	public Result<String> deleteById(Long id) {
		// 查询当前分类是否关联了菜品，如果关联了就抛出业务异常
		Integer count = dishMapper.countByCategoryId(id);
		if (count > 0) {
			// 当前分类下有菜品，不能删除
			throw new DeletionNotAllowedException(MessageConstant.CATEGORY_BE_RELATED_BY_DISH);
		}

		// 查询当前分类是否关联了套餐，如果关联了就抛出业务异常
		count = setmealMapper.countByCategoryId(id);
		if (count > 0) {
			// 当前分类下有菜品，不能删除
			throw new DeletionNotAllowedException(MessageConstant.CATEGORY_BE_RELATED_BY_SETMEAL);
		}

		// 删除分类数据
		categoryMapper.deleteById(id);

		return Result.success();
	}

	/**
	 * 修改分类
	 *
	 * @return:
	 * @param:
	 */
	@Override
	public Result<String> updateCategoryById(CategoryDTO categoryDTO) {
		Category category = new Category();
		BeanUtils.copyProperties(categoryDTO, category);

		categoryMapper.updateCategoryById(category);

		return Result.success();
	}

	/**
	 * 启用、禁用分类
	 *
	 * @return:
	 * @param:
	 */
	@Override
	public Result<String> startOrStop(Integer status, Long id) {
		Category category = Category.builder().id(id).status(status).build();
		categoryMapper.updateCategoryById(category);

		return Result.success();
	}

	/**
	 * 根据类型查询分类
	 *
	 * @return:
	 * @param:
	 */
	@Override
	public Result<List<Category>> selectByCategoryType(Integer type) {
		/**
		 * 将菜品分类数据存入到缓存中，查询步骤：
		 * 1. 如果缓存中有，直接返回
		 * 2. 缓存中没有，查询数据库
		 */
		List<Category> categoryList = (List<Category>) redisTemplate.opsForValue().get(RedisConstant.CATEGORY_CACHE_PREFIX +
			type);
		if (!CollectionUtils.isEmpty(categoryList)) {
			log.warn("从 Redis 中查询数据");
			return Result.success(categoryList);
		}
		log.warn("从数据库中查询数据");
		categoryList = categoryMapper.selectByCategoryType(type);
		// 存入缓存中
		redisTemplate.opsForValue().set(RedisConstant.CATEGORY_CACHE_PREFIX + type,
			categoryList,
			60 * 60,
			TimeUnit.SECONDS
		);
		return Result.success(categoryList);
	}
}
